package com.ruoyi.common.utils;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.xml.bind.DatatypeConverter;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;

/**
 * 字节操作工具类
 # @description 与嵌入式软件数据交互过程中，必然涉及各种的、大量的字节操作场景。如：16进制与10进制、2进制间的转换，字符串、byte数组与int之间的转换等，故此有此核心工具类的沉淀。
 * @version v1.0
 * @create-time 2022/12/23 18:18
 * @description ...
 */
@Slf4j
public class BytesUtils {
    private static final Logger logger = LoggerFactory.getLogger(BytesUtils.class);

    /**
     * 单个字节的位长
     * 1byte = 8 bit
     * 1个16进制位 占 4 bit => 1个字节可代表 2 个 16进制位, 1 个16进制位 = 0.5 个字节
     **/
    public final static int BYTE_BIT_LENGTH = 8;

    /**
     * 0x00 占位符 的 UTF8 表示
     * 0x00 (在 ASCII 表中表示 NULL 字符)
     **/
    public final static String PLACEHOLDER_UTF8_0x00 = "\u0000";
    /** 0x00 占位符 的 16进制 表示 **/
    public final static String PLACEHOLDER_HEX_0x00 = "0x00";

    /**
     * 判断对象是否为 byte 数组
     * @note 补充 byteArrayToString
     *  byte 数组转字符串的方法: new String( new String( (byte []) javaObject) , "UTF-8" )
     * @reference-doc
     *  [1] java判断object是否为byte数组 - 51CTO - https://blog.51cto.com/u_16213452/11581409
     * @param object
     * @return
     */
    public static Boolean isByteArray(Object object){
        if (object == null) {
            return false; // 如果对象为null，则直接返回false
        }
        if (!object.getClass().isArray()) {//判断是否为数组
            return false; // 如果对象不是数组，则直接返回false
        }
        //if (object.getClass().getComponentType() != byte.class) {//方法1
        if(!object.getClass().getComponentType().getCanonicalName().equalsIgnoreCase("byte")) {//方法2
            return false; // 如果数组的组件类型不是byte，则返回false
        }
        return true; // 如果数组的组件类型是byte，则返回true
    }

    /** 合并2个字节数组 **/
    public static byte[] merge(byte[] array1, byte[] array2) {
        byte[] combined = new byte[array1.length + array2.length];
        System.arraycopy(array1, 0, combined, 0, array1.length);
        System.arraycopy(array2, 0, combined, array1.length, array2.length);
        return combined;
    }

    /**
     * 字节转 无符号整数
     * @param aByte
     * @return
     * @usage
     *   byte b = (byte) 0xc4;
     *   toUnsignedInt(b) = 196
     */
    public static int toUnsignedDecimal(byte aByte){
        return Byte.toUnsignedInt(aByte);
    }

    /**
     * X进制数的字符串转10进制的有符号整型
     * @return
     * @sample
     *  radixNumberStringToDecimal("01070500", 16) = 17237248
     *  radixNumberStringToDecimal("1070500", 16) = 17237248
     *  radixNumberStringToDecimal("1A3F", 16) = 6719
     *  radixNumberStringToDecimal("-1A3F", 16) = -6719
     *  radixNumberStringToDecimal("FFFFFFFFFFFFFFE1", 16) : 将报错
     */
    public static Long radixNumberStringToDecimal(String xRedixNumberString, int radix){
        return Long.parseLong(xRedixNumberString, radix);
    }

    /**
     * X进制数的字符串转10进制的无符号整型
     * @return
     * @sample
     *  radixNumberStringToUnsignedDecimal("01070500", 16) = 17237248
     *  radixNumberStringToUnsignedDecimal("1070500", 16) = 17237248
     *  radixNumberStringToUnsignedDecimal("1A3F", 16) = 6719
     *  radixNumberStringToUnsignedDecimal("FFFFFFFFFFFFFFE1", 16) = -31
     */
    public static Long radixNumberStringToUnsignedDecimal(String xRedixNumberString, int radix){
        return Long.parseUnsignedLong(xRedixNumberString, radix);
    }

    public static String INTEGER_ARRAY_STRING_SEPARATOR = ".";//整型数组字符换的分隔符

    /**
     * 字节数组转 整型数组（以字符串组合而成）
     * @param hexString
     * @param separator
     * @return null or integerArrayString
     * @usage "00102030","." => "1.2.3"
     */
    public static String hexStringToIntegerArrayString(String hexString, String separator){
        if(StringUtils.isEmpty(hexString) ){// null or ""
            return null;
        }
        if(hexString.length()%2 != 0){//字节数据残缺
            throw new RuntimeException("Fail to convert to integer array string cause that hex string data is abnormal!hexString:" + hexString);
        }
        separator = ObjectUtils.isEmpty(separator)?"":separator;
        int byteSize = hexString.length()/2;
        StringBuilder resultBuilder = new StringBuilder();
        for(int i=0;i<byteSize;i++){
            String hexByteStr = hexString.substring(i*2,i*2 + 2); //单个字节的16进制表示 ; eg: "48"
            resultBuilder.append(Integer.parseInt( hexByteStr, 16) );// eg: "48" => 72
            resultBuilder.append(separator);
        }
        //删除最后一个多余的字符
        resultBuilder.deleteCharAt(resultBuilder.length()-1);
        resultBuilder.toString();
        return resultBuilder.toString();
    }

    public static String hexStringToIntegerArrayString(String hexString){
        return hexStringToIntegerArrayString(hexString, INTEGER_ARRAY_STRING_SEPARATOR);
    }

    public static void main(String[] args) {
        hexStringToIntegerArrayString("4856", ";");
    }

    public static Integer [] hexStringToLongArray(String hexString){
        if(StringUtils.isEmpty(hexString) ){// null or ""
            return null;
        }
        if(hexString.length()%2 != 0){//字节数据残缺
            throw new RuntimeException("Fail to convert to integer array string cause that hex string data is abnormal!hexString:" + hexString);
        }
        int byteSize = hexString.length()/2;
        Integer [] integers = new Integer[] { byteSize };
        StringBuilder resultBuilder = new StringBuilder();
        for(int i=0;i<byteSize;i++){
            String hexByteStr = hexString.substring(i*2,i*2 + 2); //单个字节的16进制表示 ; eg: "48"
            integers[i] = Integer.parseInt( hexByteStr, 16);// "48" => 72
        }
        return integers;
    }

    /**
     * 字节转二进制字符串
     * @note
     *  单个字节 : 'a' => 97 => 0x61 => 01100001 (二进制) | 兼容 : 无符号数、有符号数
     *      byteToBit( (byte) 0x61 ) = "01100001"
     *  单个字节 : 250 => 0xFA = 11111010 (二进制) | 无符号数
     *      byteToBit( (byte) 0xFA ) = "11111010"
     * @param b
     * @return
     */
    public static String byteToBinaryString(byte b) {
        return "" +
                (byte) ((b >> 7) & 0x1) +
                (byte) ((b >> 6) & 0x1) +
                (byte) ((b >> 5) & 0x1) +
                (byte) ((b >> 4) & 0x1) +
                (byte) ((b >> 3) & 0x1) +
                (byte) ((b >> 2) & 0x1) +
                (byte) ((b >> 1) & 0x1) +
                (byte) ((b >> 0) & 0x1);
    }

    /**
     * 十六进制字符串 转 二进制字符串
     * @note
     *  hexStringToBinaryString( "61" ) = "01100001" | 'a' => 97 => 0x61 => "01100001"
     *  hexStringToBinaryString( "FA" ) = "11111010"
     *  hexStringToBinaryString( "48656c6c6f" ) = "0100100001100101011011000110110001101111"
     *      即 "01001000 01100101 01101100 01101100 01101111"
     * @param hexString
     * @return
     */
    public static String hexStringToBinaryString(String hexString) {
        byte[] bytes = hexStringToBytes(hexString);
        StringBuilder s = new StringBuilder(64);
        for (byte aByte : bytes) {
            s.append(BytesUtils.byteToBinaryString(aByte));
        }
        return s.toString();
    }
    /**
     public static String hexStringToBinaryString(String hexString){
     if(ObjectUtils.isEmpty(hexString) || hexString.length()%2 != 0){
     return "";
     }
     StringBuilder binaryString = new StringBuilder();
     String tmp;
     for(int i=0;i<hexString.length(); i++){
     tmp = "0000" + Integer.toBinaryString( Integer.parseInt(hexString.substring(i, i+1), 16) );
     binaryString.append( tmp.substring( tmp.length() -4 ) );

     //String binary = Integer.toBinaryString(Integer.parseInt(hexString.charAt(i) + "", 16));
     //binaryBuilder.append(String.format("%4s", binary).replace(' ', '0')); // 格式化为4位二进制数
     }

     logger.info("hexString : {}, binaryString : {}", hexString, binaryString);
     return binaryString.toString();
     }
     **/

    /**
     * 字节数组转十六进制表示的字符串
     * @note
     *  'H' => 72 => 0x48 ; 'e' => 101 => 0x65
     *  bytesToString(new byte[] { 0x48, 0x65 }) = "4865"
     * @param byteArray
     * @return
     */
    public static String bytesToHexString(byte[] byteArray) {
        StringBuilder builder = new StringBuilder();
        if (byteArray == null || byteArray.length <= 0) {
            return null;
        }
        String hv;
        for (int i = 0; i < byteArray.length; i++) {
            // 以十六进制（基数 16）无符号整数形式返回一个整数参数的字符串表示形式，并转换为大写
            hv = Integer.toHexString(byteArray[i] & 0xFF);
            if (hv.length() < 2) {
                builder.append(0);
            }
            builder.append(hv);
        }
        return builder.toString();
    }
    /**
     public static String bytesToHexString(byte[] byteArray) {
     StringBuilder stringBuilder = new StringBuilder("");
     if (byteArray != null) {
     for (int i = 0; i < byteArray.length; ++i) {
     stringBuilder.append( byteToHexString(byteArray[i]) );
     }
     }
     return stringBuilder.toString();
     }
     **/

    /**
     * 字符串转字节数组
     * @note
     *  stringToBytes("Hello World", Charset.forName("UTF-8")) => [72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100]
     *  stringToBytes("娃哈哈", Charset.forName("UTF-8")) => [-27, -88, -125, -27, -109, -120, -27, -109, -120]
     * @param text
     * @return
     */
    public static byte [] stringToBytes(String text, Charset charset){
        if(ObjectUtils.isEmpty(text)){
            throw new RuntimeException("text is empty! text : " + text);
        }
        return charset==null?text.getBytes():text.getBytes(charset);
    }

    /**
     * (多字节的)二进制字符串转二进制数组
     * @note <p>需了解本方法的局限性</p>
     *  <p>单个字节的二进制字符串 必须满足 java byte(8bit、有符号数) 的取值范围 [-128, 127]</p>
     *  <p>正确示例: binaryStringToBytes("01001000") => out: [72]</p>
     *  <p>错误示例: binaryStringToBytes("11111010") => 0xFA = 250 = 0b1111 0b00001010" => out: [-6] (错误结果，因:超出有符号数byte取值范围)</p>
     * @param binaryString
     * @return
     */
    public static byte[] binaryStringToBytes(String binaryString) {
        if(ObjectUtils.isEmpty(binaryString)){
            throw new RuntimeException("Fail to convert binary array cause by the empty binary string! binaryString : " + binaryString);
        }
        if(binaryString.length() %BYTE_BIT_LENGTH != 0){//不是4的倍数
            throw new RuntimeException("Fail to convert binary array cause that the binary string is not a multiple of " + BYTE_BIT_LENGTH + "! binaryString : " + binaryString);
        }

//        char [] charArray =  binaryString.toCharArray() // string 内部由 2个字节的char组成的 char 数组 , 故: 这种转换做法有风险
//        byte [] binaryArray = new byte [ binaryString.length() ];
//        for (int i = 0; i < charArray.length; i ++) {
//            //binaryArray[i] = (byte)charArray[i]; // java char 占用 : 2个字节 ; java byte 占用 1个字节 => 这种做法不正确
//            binaryArray[i]
//        }

        int byteSize = binaryString.length()/BYTE_BIT_LENGTH;
        byte[] binaryArray = new byte[byteSize];
        for (int i = 0; i < byteSize; i ++) {
            String byteBinaryStr = binaryString.substring(i*BYTE_BIT_LENGTH, i*BYTE_BIT_LENGTH + BYTE_BIT_LENGTH);//sample "01001000"
            binaryArray[i] = binaryStringToByte(byteBinaryStr);
        }
        return binaryArray;
    }

    /**
     * (多字节的)二进制字符串转 ByteBuffer
     * @note 解决 java byte 类型仅支持有符号数 的 取值范围 [-128, 127] 的局限性 (ByteBuffer : 支持无符号数)
     * 在Java中，如果你想要处理无符号的byte数组，你可以使用ByteBuffer类，它可以以大端或小端格式读写字节。
     * 由于Java中的byte类型是有符号的，范围为-128到127，所以无符号的byte数组需要特别处理。
     * 例如:
     *      ByteBuffer buffer = ByteBuffer.allocate(5);// 创建一个包含无符号byte的ByteBuffer
     *      buffer.put((byte) 0x80); // 256的二进制补码表示为1000 0000，是一个负数 | 注意，put 方法 传入的是 byte 值，它们会以其补码形式存储。
     *      buffer.put((byte) 0xFF); // 255的二进制补码表示为1111 1111
     *      buffer.flip(); // 翻转Buffer，准备读取
     *      // 读取无符号 byte
     *      int unsignedByte1 = buffer.get() & 0xFF; // 将有符号byte转换为无符号 : 256
     *      int unsignedByte2 = buffer.get() & 0xFF; // 将有符号byte转换为无符号 : 255
     * 当我们想要读取这些值时，我们使用 get() 方法，并将得到的值与255进行"与"操作（0xFF），这样可以确保我们得到无符号的值。
     * 这种方法适用于处理单个 byte 值，如果你需要处理更大的无符号数，你可能需要多次调用get()方法，并进行适当的位操作来组成一个无符号整数。
     * @usage
     *   ByteBuffer byteBuffer = binaryStringToByteBuffer("1111101011111011");//0xFA , 0xFB
     *   byteBuffer.flip();
     *   int value1 = byteBuffer.get(0) & 0xFF;//250
     *   int value2 = byteBuffer.get(1) & 0xFF;//251
     * @param binaryString
     * @return
     */
    public static ByteBuffer binaryStringToByteBuffer(String binaryString) {
        int byteSize = binaryString.length()/BYTE_BIT_LENGTH;
        if(binaryString.length() % BYTE_BIT_LENGTH != 0){
            throw new RuntimeException("the binary string must be `" + "`'s times!");
        }

        // 创建一个包含 无符号 byte 的 ByteBuffer
        ByteBuffer buffer = ByteBuffer.allocate(byteSize);
        for(int i=0;i<byteSize;i++){
            String oneByteBinaryString =  binaryString.substring(i*BYTE_BIT_LENGTH, i*BYTE_BIT_LENGTH + BYTE_BIT_LENGTH);//sample "01001000"
            int value = oneByteBinaryStringToInt(oneByteBinaryString);
            buffer.put( (byte) value );
        }
        return buffer;
    }

    /**
     * 单字节的二进制字符串转 Int 整型
     * @sample
     *  oneByteBinaryStringToInt("1010") => out : 10 => 0xA
     *  oneByteBinaryStringToInt("11111010") => out : 250 => 0xFA
     * @param oneByteBinaryString
     * @return
     */
    public static Integer oneByteBinaryStringToInt(String oneByteBinaryString){
        Integer value = Integer.parseInt(oneByteBinaryString, 2); // 转换为十进制整数
        return value;
    }

    /**
     * 将位长为8位的二进制字符串转为 1个字节
     * @note
     *  注意避坑 : java byte 的局限性
     *      1. byte 取值范围是 [-128, +127]. Java中的 byte 数据类型是 8 位、有符号的，其取值范围是从 -128 到 127
     *      2. 基于1，入参(`binaryString`) 的取值范围 : [0b10000000(即-128) , 0b11111111(即-1)] U [0b00000000, 0b01111111]
     * @param binaryString
     *  sample "01001000" => 72 ; "01111111" => 127
     * @return
     */
    public static byte binaryStringToByte(String binaryString){
        int x = 0;// 注 : int 占用 4 个字节
        for(int j=0; j < BYTE_BIT_LENGTH; j++){
            String currentBinaryBit = binaryString.substring(BYTE_BIT_LENGTH-1-j, (BYTE_BIT_LENGTH-1-j)+1);
            x = x + Integer.parseInt( currentBinaryBit ) * ( (int) Math.pow(2, j) );//强制类型转换会直接截断小数部分
        }
        return (byte) x;
    }

    /**
     * 二进制字符串转十六进制字符串
     * @param binaryString
     * @sample binaryStringToHexString("1111101011111011") => "FAFB" (即: 0xFA, 0xFB)
     *
     */
    public static String binaryStringToHexString(String binaryString){
        byte[] binaryArray = binaryStringToBytes(binaryString);

        StringBuilder hexStr = new StringBuilder();
        int byteSize = binaryArray.length;
        for(int i=0; i< byteSize; i++){
            hexStr.append( byteToHexString( binaryArray[i] ) );
        }
        return hexStr.toString();
    }

    /**
     * char 转 byte 数组[固定2个字节]
     * @description 背景 : char类型即可以存储英文字母，也可存储汉字；汉字在java中使用Unicode编码占两个字节
     * @param c
     * @return
     * @sample
     *  charTo2Bytes('G') = [0, 71]
     *  charTo2Bytes('哇') = [84, -57]
     */
    public static byte[] charTo2Bytes(char c) {
        byte[] b = new byte[2];
        b[0] = (byte) ((c & 0xFF00) >> 8);
        b[1] = (byte) (c & 0xFF);
        return b;
    }

    /**
     * 十六进制字符串转byte数组
     * @param hexString | sample "48656c6c6f"
     * @return | sample [72, 101, 108, 108, 111] 即 [0x48, 0x65, 0x6c, 0x6c, 0x6f ] //注 : 以0x开始的数据表示16进制
     */
    /**
     * 将Hex String转换为Byte数组
     * @param hexString the hex string
     * @return the byte [ ]
     */
    public static byte[] hexStringToBytes(String hexString) {
        if (org.apache.commons.lang3.StringUtils.isBlank(hexString)) {
            return null;
        }
        //hexString = hexString.toLowerCase();
        final byte[] byteArray = new byte[hexString.length() >> 1];
        int index = 0;
        for (int i = 0; i < hexString.length(); i++) {
            if (index > hexString.length() - 1) {
                return byteArray;
            }
            byte highDit = (byte) (Character.digit(hexString.charAt(index), 16) & 0xFF);
            byte lowDit = (byte) (Character.digit(hexString.charAt(index + 1), 16) & 0xFF);
            byteArray[i] = (byte) ((highDit << 4) | (lowDit & 0xFF));
            index += 2;
        }
        return byteArray;
    }
    /**
     public static byte[] hexStringToBytes(String hexString){
     //String hexString = "48656c6c6f"; // 示例十六进制字符串 "Hello"
     byte[] byteArray = DatatypeConverter.parseHexBinary(hexString);
     return byteArray;
     }
     **/

    /**
     * 十六进制字符串转字节数组 | 方法2
     * @note 局限性 : byte 的取值范围 : [-128, 127]
     *  例如 错误的入参示范 :  hexStringToBytes("fffafb") = [-1, -6, -5] (错误结果)
     * @param hexStr
     * @return
     */
    /**
     public static byte[] hexStringToBytes(String hexStr) {
     if (!StringUtils.isEmpty(hexStr) && hexStr.length() % 2 == 0) {
     byte[] data = null;

     try {
     char[] chars = hexStr.toCharArray();
     data = Hex.decodeHex(chars);
     } catch (DecoderException var3) {
     logger.error(var3.getMessage(), var3);
     }

     return data;
     } else {
     return null;
     }
     }
     **/

    /**
     * 字节数组 转 十六进制数组字符串
     * @usage bytesToHexArrayString( new byte [] { 0x34, 0x67} ) = [0x34,0x67]
     * @param byteArray
     * @return
     */
    public static String bytesToHexArrayString(byte[] byteArray) {
        StringBuffer sb = new StringBuffer();
        sb.append("[");
        if (byteArray != null) {
            for (int i = 0; i < byteArray.length; ++i) {
                sb.append("0x").append(byteToHexString(byteArray[i]));
                if (i < byteArray.length - 1) {
                    sb.append(",");
                }
            }
        }

        sb.append("]");
        return sb.toString();
    }

    /**
     * 字节转16进制字符串
     * @sample byteToHexString( (byte)0xFA ) = "FA"
     * @param aByte
     * @return
     */
    public static String byteToHexString(byte aByte) {
        char[] digit = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
        char[] tempArr = new char[]{digit[aByte >>> 4 & 15], digit[aByte & 15]};
        String s = new String(tempArr);
        return s;
    }

    /**
     * INT 转 16进制字符串
     * @param v
     * @return
     * @usage intToHexString(255) => "ff"
     */
    public static String intToHexString(int v) {
        String hexStr = Integer.toHexString(v);
        if (hexStr.length() % 2 != 0) {
            hexStr = "0" + hexStr;
        }

        return hexStr;
    }



    /* ------------------------ 如下方法，待测验 TODO ---------------------- */

    /**
     * 从输入流中获取字节数组
     * @param in
     * @return
     */
    public static byte[] getBytes(InputStream in) {
        byte[] data = null;

        try {
            byte[] buffer = new byte[1024];

            int len;
            for (; (len = in.read(buffer)) > 0; data = addArray(data, buffer, len)) {
            }
        } catch (IOException var4) {
            logger.error(var4.getMessage(), var4);
        }

        return data;
    }

    public static byte[] addArray(byte[] source, byte[] addedAry) {
        return addArray(source, addedAry, addedAry.length);
    }

    public static byte[] addArray(byte[] source, byte[] addedAry, int availableAddedAryLength) {
        if (addedAry == null) {
            return source;
        } else {
            byte[] buf = new byte[(source == null ? 0 : source.length) + availableAddedAryLength];
            int i;
            if (source != null) {
                for (i = 0; i < source.length; ++i) {
                    buf[i] = source[i];
                }
            }

            for (i = 0; i < availableAddedAryLength; ++i) {
                buf[(source == null ? 0 : source.length) + i] = addedAry[i];
            }

            return buf;
        }
    }

    public static int contains(byte[] source, byte[] data) {
        if (source == null || data == null) { return -1; }
        if (source.length >= data.length && data.length != 0) {
            int pos = -1;
            for (int i = 0; i <= source.length - data.length; ++i) {
                boolean flag = true;
                for (int j = 0; j < data.length; ++j) {
                    if (source[i + j] != data[j]) { flag = false; }
                }
                if (flag) { pos = i; break; }
            }
            return pos;
        }
        return -1;
    }

    public static boolean startWith(byte[] source, byte[] startData) {
        if (source == null) {
            return false;
        } else if (startData == null) {
            return false;
        } else if (source.length >= startData.length && startData.length != 0) {
            boolean flag = true;

            for (int i = 0; i < startData.length; ++i) {
                if (source[i] != startData[i]) {
                    flag = false;
                    break;
                }
            }

            return flag;
        } else {
            return false;
        }
    }

    public static boolean endWith(byte[] source, byte[] endData) {
        if (source == null) {
            return false;
        } else if (endData == null) {
            return false;
        } else if (source.length >= endData.length && endData.length != 0) {
            boolean flag = true;

            for (int i = 0; i < endData.length; ++i) {
                if (source[source.length - endData.length + i] != endData[i]) {
                    flag = false;
                    break;
                }
            }

            return flag;
        } else {
            return false;
        }
    }

    public static byte[] removeStart(byte[] source, int len) {
        if (source == null) {
            return null;
        } else if (source.length < len) {
            return null;
        } else {
            byte[] buf = new byte[source.length - len];

            for (int i = 0; i < buf.length; ++i) {
                buf[i] = source[i + len];
            }

            return buf;
        }
    }

    public static byte[] removeEnd(byte[] source, int len) {
        if (source == null) {
            return null;
        } else if (source.length < len) {
            return null;
        } else {
            byte[] buf = new byte[source.length - len];

            for (int i = 0; i < buf.length; ++i) {
                buf[i] = source[i];
            }

            return buf;
        }
    }

    public static byte[] subByteArray(byte[] data, int beginIndex, int endIndex) {
        if (beginIndex < 0) {
            throw new IndexOutOfBoundsException("beginIndex must bigger than 0,but it is " + beginIndex + "");
        } else if (endIndex >= data.length) {
            throw new IndexOutOfBoundsException("endIndex must smaller than data lenght " + data.length + ",but it is " + endIndex + "");
        } else {
            byte[] buf = new byte[endIndex - beginIndex + 1];

            for (int i = beginIndex; i <= endIndex; ++i) {
                buf[i - beginIndex] = data[i];
            }

            return buf;
        }
    }

    public static byte[] remove(byte[] data, int start, int size) {
        if (data == null) {
            return null;
        } else if (start >= data.length) {
            throw new IndexOutOfBoundsException("start must smaller than data's length:'" + data.length + "',but it is " + start + "");
        } else if (start + size > data.length) {
            throw new IndexOutOfBoundsException("start+size must smaller than data's length:'" + data.length + "',but they are " + start + "+" + size + "");
        } else {
            byte[] buf = new byte[data.length - size];

            int i;
            for (i = 0; i < start; ++i) {
                buf[i] = data[i];
            }

            for (i = start + size; i < data.length; ++i) {
                buf[i - size] = data[i];
            }

            return buf;
        }
    }

    public static byte[] removeContains(byte[] source, byte[] data) {
        int pos;
        if (source == null) {
            return null;
        } else if (data == null) {
            return source;
        } else {
            if ((pos = contains(source, data)) == -1) {
                return source;
            } else if (source.length < data.length) {
                return null;
            } else {
                byte[] buf = new byte[source.length - data.length];

                int i;
                for (i = 0; i < pos; ++i) {
                    buf[i] = source[i];
                }

                for (i = pos + data.length; i < source.length; ++i) {
                    buf[i - data.length] = source[i];
                }

                return buf;
            }
        }
    }

    /** 打印二进制字符串 （每8bit，打印为1行）
     * @param bitString 字符串化的二进制字节流
     *  note : 长度必须为8的倍数(因: 1 byte = 8 bit)
     *  sample : "1011011110100011000011110000000000000000000000000000000000000000"
     * @param isEnable 是否启用本方法的日志打印
     **/
    public static String printBitString(String bitString, boolean isEnable){
        if( bitString == null || bitString.length() %8!=0){//长度必须是8的整数倍
            throw new RuntimeException("The length of input bit string must be an integer multiple of 8! bit string : " + bitString);
        }
        if(bitString == ""){//bitString == ""
            return "";
        }
        StringBuilder result = new StringBuilder();
        String bit8 = null;
        while (bitString.length() >= 8) {
            bit8 = bitString.substring(0, 8);//第 (0, 8] 位 ，共计 8 位
            result.append( String.format("                %s        : %s\n", bit8, BytesUtils.binaryStringToHexString(bit8)) );// 01111111 : 7F
            bitString = bitString.substring(8); //第 (8 , +∞) 位，递归
        }
        return result.toString();
    }

    /**
     * 清除十六进制字符串前缀的NULL字符(0x00)
     * @param hexString eg: "00004856"
     * @return eg: "4856"
     */
    public static String clearHexStringPrefixNullCharacters(String hexString){
        // 1. 输入验证（略，根据实际情况决定是否需要严格验证）

        // 使用StringBuilder来避免不必要的字符串拷贝
        StringBuilder sb = new StringBuilder();

        char [] hexCharArray = hexString.toCharArray();// ['0', '0', '0', '0', '4', '8', '5', '6']
        int byteSize = hexCharArray.length/2;
        char [] hexByte = new char[] { 0x00, 0x00 };//新建 2个 NULL 字节 的数组
        for(int i=0; i<byteSize; i++){
            hexByte[0] = hexCharArray[i*2];//i*2 + 0
            hexByte[1] = hexCharArray[i*2 + 1];//i*2 + 1
            if(hexByte[0] == '0' && hexByte[1] == '0') {//当前字节为 0x00 : 被清理掉，继续下移到下一个字节
                continue;
            } else {//循环终止，截取剩余的字符 即 清理的最终结果
                sb.append(hexCharArray, i*2, hexCharArray.length -2*i );
                /**
                 * 底层调用 : System.arraycopy(var1=hexCharArray, var2=i*2, this.value, this.count=0, var3=length);
                 * @reference-doc [1] System.arraycopy方法详解 - CSDN - https://blog.csdn.net/Rex_WUST/article/details/95791456
                 * @demo
                 *  byte[] originalBytes={1,2,3,4,5,6};
                 *  byte[] targetBytes = {7,8,9};
                 *  System.arraycopy(originalBytes, 2, targetBytes , 0, 3); //从源数组下标为2的元素开始，复制3个元素。然后以目标数组下标为0的元素为起点，开始拷贝
                 *  运算结果 : [3,4,5]
                 */
                break;
            }
        }

        return sb.toString(); // 返回处理后的字符串
    }
}
